<?php
/**
 * 校正用户上一天最终的考勤状态
 *@author coldarmy
 * */
apf_require_class('Oa_Job_Attendance_Abstract');
apf_require_class('Const_LeaveType');
apf_require_class('Tools_Tools');
class Oa_Job_Attendance_AdjustYesterdayStatus extends Oa_Job_Attendance_Abstract {

    /** 考勤系统读 **/
    private $readdb = "attendance_slave";
    /** 考勤系统写 **/
    private $writedb = "attendance_master";

    private $date = '';
    private $startwork = 910;
    private $endwork = 1800;
    private $chidao = 930;
    private $pmstart = 1400;
    private $zaotui = 1730;
    private $sp_endwork =0;//特殊下班的时间点
    private $sp_startwork =0;//特殊上班时间点
    public function run($params = 0){
        $this->log("开始准备校正数据...");
        //初始化需要校正的日期,如无指定，取上一天
        $this->date = date('Ymd',mktime(0,0,0,date('m'),date('d')-1,date('Y')));
        if ($params) {
            $this->date = intval(date('Ymd',strtotime($params)));
        }
        //特殊下班时间
        $special_leave_time = Tools_Tools::get_instance()->special_leave_time();
        $yesterday = date('Y-m-d',strtotime($this->date));
        if(isset($special_leave_time[$yesterday])){
            $sp_endtime = intval(date('Hi',strtotime($special_leave_time[$yesterday]['leave_time'])));
            $sp_starttime = intval(date('Hi',strtotime($special_leave_time[$yesterday]['start_time'])));
            if($sp_starttime > $this->startwork){
                $this->sp_startwork = $sp_starttime;
            }
            if($sp_endtime < $this->endwork){
                $this->sp_endwork = $sp_endtime;
            }
        }
        $last_timetamp = strtotime($this->date);
        //第一步：获取所有需打卡在职员工信息，（提醒初始化数据时，是否为正常上班工作日）
        $userinfo =  $this->get_all_user_info($last_timetamp);
        if (empty($userinfo)) {
            $this->log("用户信息获取失败!");
            die();
        }
        $uids = array();
        $user_types = array();
        foreach ($userinfo as $key => $val) {
            $uids[] = $val['user_id'];
            $user_types[$val['user_id']]['user_type'] = $val['user_type'];
            $user_types[$val['user_id']]['user_type_date'] = $val['user_type_date'];
        }

        //第二步:获取每个人对应的打卡记录 ar = access record
        $ar = $this->get_user_access_day_record($uids);
        //找出异常数据
        $deal_user_data = array();
        $deal_user_ids = array();
        $right_user_ids  = array();
        foreach ($uids as $key => $val) {
            if(isset($ar[$val])) {
                if($ar[$val]['start_work'] > $this->startwork || $ar[$val]['end_work'] < $this->endwork) {
                    $deal_user_data[] = $ar[$val];
                    $deal_user_ids[] = $val;
                }else{
                    $right_user_ids[] = $val;
                }
            } else {
                $deal_user_data[] = array('user_id' => $val,'start_work' => 0,'end_work' => 0);
                $deal_user_ids[] = $val;
            }
        }
        //第三步：对存在异常的数据进行处理
        $this->deal_unnormal_data($deal_user_data,$deal_user_ids,$user_types);
        //第四步：正常验证
        $this->_right_check($right_user_ids,$user_types);
        $this->log("数据校正完毕");
    }

    /**
     * 对存在的异常数据进行处理
     * @param array() $data
     * @return void
     * **/
    private function deal_unnormal_data($datalist,$uids,$user_types) {
         if (empty($datalist)) {
             return;
         }
         $this->log("开始整理非正常考勤的用户状态......");
         //第一步：取出最终考勤状态及公出的记录数据
         $status = $this->get_special_day_status($uids);
         $gongchu = $this->get_leave_gongchu($uids);
         //第二步：数据处理，以异常数据作为基点遍历数据
         foreach ($datalist as $key => $val) {
            $cuser = $status[$val['user_id']];
            $guser = $gongchu[$val['user_id']];
            //监控下午状态
            if ($cuser['pm_type'] && $cuser['am_type'] && $cuser['am_leave_status'] == Const_LeaveType::LEAVE_STATUS_PASS && $cuser['pm_leave_status'] == Const_LeaveType::LEAVE_STATUS_PASS) {//有请假且请假批准
                //已校正下午状态，直接continue
                continue;
            }
            //判断是否有公出
            $is_normal_am = false;
            $is_normal_pm = false;
            $is_all_day_leave = 0;
            if($guser) {
                $is_all_day_leave = 1;
                //取所有公出校正数据,其中一条满足即退出
                foreach ($guser as $k => $v) {
                    $gstart = intval(date('Hi',strtotime($v['start_time'])));
                    $gend = intval(date('Hi',strtotime($v['end_time'])));
                    //当天有打卡记录的
                    if($val['end_work'] && $val['start_work']) {
                        //上午能覆盖
                        if ($gstart <= $this->startwork && $gend >= $val['start_work']) {
                            $is_normal_am = true;
                        }elseif($this->sp_startwork && $gstart <= $this->sp_startwork && $gend >= $val['start_work']){
                            $is_normal_am = true;
                        }
                        //下午能覆盖
                         if ($gstart <= $val['end_work'] && $gend >= $this->endwork) {
                             $is_normal_pm = true;
                         }elseif($this->sp_endwork && $gstart <= $val['end_work'] && $gend >= $this->sp_endwork){
                             $is_normal_pm = true;
                         }
                    } else {//无打卡记录，
                        //上午覆盖
                        if ($gstart <= $this->startwork && $gend >= 1200) {
                            $is_normal_am = true;
                        }elseif($this->sp_startwork && $gstart <= $this->sp_startwork && $gend >= 1200){
                            $is_normal_am = true;
                        }
                        //下午覆盖
                        if ($gstart <= 1400 && $gend >= $this->endwork) {
                            $is_normal_pm = true;
                        }elseif($this->sp_endwork && $gend >= $this->sp_endwork && $gstart <= 1400){
                            $is_normal_pm = true;
                        }
                    }
                }
            }
            //特殊班别
            $user_type = $user_types[$val['user_id']]['user_type'];
            $user_type_date = intval($user_types[$val['user_id']]['user_type_date']);
            $data = array();
            if($user_type && $user_type_date && $user_type_date <= $this->date){//特殊班别
                //特殊班别,全天缺勤，没有公出，且没有请假，出差
                //有请假，未批准
                if((!$val['start_work'] && !$val['end_work'] && !$is_all_day_leave && !$cuser['am_type'] && !$cuser['pm_type'])||( $cuser['am_type'] && $cuser['am_leave_status']== Const_LeaveType::LEAVE_STATUS_AUDIT ) ||($cuser['pm_type'] && $cuser['am_leave_status']== Const_LeaveType::LEAVE_STATUS_AUDIT)){
                    $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_3;
                    $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_4;
                    $data['days'] = 1;
                }else{//之上至少一次
                    $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                    $data['is_later'] = 0;
                    $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                    $data['leave_early'] =0;
                    $data['days'] = 0;
                }
            }else{//非特殊班别
                if($cuser['am_leave_status']!=Const_LeaveType::LEAVE_STATUS_PASS && (!$cuser['am_type'] || $cuser['am_leave_status'] == Const_LeaveType::LEAVE_STATUS_AUDIT)){//没有请假或者请假未审核
                    if(!$is_normal_am) {//上午异常
                        if($this->sp_startwork && (!$val['start_work'] || $val['start_work'] > $this->sp_startwork)){//上午缺勤
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_3;
                            $data['days'] = 0.5;
                        }elseif(!$this->sp_startwork && (!$val['start_work'] ||  $val['start_work'] > $this->chidao)){//缺勤
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_3;
                            $data['days'] = 0.5;
                        }elseif(!$this->sp_startwork && $val['start_work'] && $val['start_work'] > $this->startwork){//迟到
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_1;
                            $data['is_later'] = 1;
                            $data['days'] = 0;
                        }elseif($this->sp_startwork && $val['start_work'] && $val['start_work'] <= $this->sp_startwork){
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                            $data['days'] = 0;
                        }elseif(!$this->sp_startwork && $val['start_work'] <= $this->startwork){
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                            $data['is_later'] = 0;
                        }
                    }else{
                        $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                        $data['days'] = 0;
                    }
                }
                //缺勤和公出修改状态，没有am_type
                if($cuser['pm_leave_status']!=Const_LeaveType::LEAVE_STATUS_PASS &&  (!$cuser['pm_type'] || $cuser['pm_leave_status'] == Const_LeaveType::LEAVE_STATUS_AUDIT)){//没有请假或者请假未审核
                    if(!$is_normal_pm){//下午异常
                        if ($val['end_work'] < $this->zaotui) {
                            if($this->sp_endwork && $val['end_work'] >= $this->sp_endwork){
                                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                            }else{//缺勤
                                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_4;
                                if(isset($data['days'])){
                                    $data['days'] = $data['days'] + 0.5;
                                }else{
                                    $data['days'] = $cuser['days'] + 0.5;
                                }
                            }
                        } elseif ($val['end_work'] >= $this->zaotui && $val['end_work'] < $this->endwork) {//早退
                           if($this->sp_endwork && $val['end_work'] >= $this->sp_endwork){//正常
                                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                            }elseif(!$this->sp_endwork){//早退
                                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_2;
                                $data['leave_early'] = 1;
                            }
                        } elseif($val['end_work'] >=$this->endwork && $val['start_work'] <$this->endwork) {
                            $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                            $data['leave_early'] = 0 ;
                        }
                    }else{
                        $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                    }
                }
            }
            if(!empty($data)){
                $this->change_user_status($data,$val['user_id']);
            }
         }
         unset($datalist);
    }
    /**
     * 对可能存在的异常数据进行处理
     * @param array() $data
     * @return void
     * **/
    private function _right_check($uids,$user_types) {
        if (empty($uids)) {
            return;
        }
        $this->log("开始整理正常考勤的用户状态......");
        //第一步：取出最终考勤状态及公出的记录数据
        $status = $this->get_special_day_status($uids);
        //第二步：数据处理，遍历数据
        foreach ($status as $key => $val) {
            if($val['am_status'] != Const_LeaveType::KQ_AM_STATUS_5 || $val['pm_status'] != Const_LeaveType::KQ_PM_STATUS_6){
                $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                $this->change_user_status($data,$val['user_id']);
            }
        }
    }
    /**
     * 调整处理最终状态
     * @param array $data
     * **/
    private function change_user_status($data,$uid) {
        if (empty($data) || empty($uid)) {
            return;
        }
        $value = '';
        foreach ($data as $key => $val) {
            $value .= $key." = '{$val}',";
        }
        $value = substr($value,0,-1);
        $sql = "UPDATE user_day_status SET $value WHERE user_id = {$uid} AND dateline = {$this->date}";
        $this->execute($sql,array(),$this->writedb);
    }

    /**
     * 取出指定时间的最终打卡记录
     * @param array() $uids
     * @return array
     * **/
    private function get_special_day_status($uids) {
        $result = array();
        if (empty($uids)) {
            return $result;
        }
        $uids = implode(',',$uids);
        $sql = "SELECT * FROM user_day_status WHERE user_id in ({$uids}) AND dateline = {$this->date}";
        $tmp = $this->get_db_rows($sql,$this->writedb,array());
        if($tmp) {
            foreach ($tmp as $key => $val) {
                $result[$val['user_id']] = $val;
            }
        }
        return $result;
    }

    /**
     * 获取公出的记录
     * TO DO 提醒冗余公出时间点
     * @param array() $uids
     * @return array 用户可能对应多条数据
     * **/
    private function get_leave_gongchu($uids) {
        $result = array();
        if (empty($uids)) {
            return $result;
        }
        //取出公出的记录
        $uids = implode(',',$uids);
        $gtype = Const_LeaveType::LEAVE_TYPE_GONGCHU;
        $sql = "SELECT * FROM user_leave_daily WHERE leave_type = {$gtype} AND user_id  in ({$uids}) AND dateline = {$this->date}";
        $tmp = $this->get_db_rows($sql,$this->writedb,array());
        if(empty($tmp)) {
            return $result;
        }
        //取出公出详细时间
        $lids =  array();
        foreach ($tmp as $key => $val) {
            $lids[] = $val['leave_id'];
        }
        $lids = implode(',',$lids);
        $lsql = "SELECT id,user_id,start_time,end_time FROM leave_record WHERE id in ({$lids})";
        $tmp = $this->get_db_rows($lsql,$this->writedb,array());
        foreach ($tmp as $key => $val) {
            $result[$val['user_id']][] = $val;
        }
        return $result;
    }

    /**
     * 获取所有在职员工信息
     * @params int $last_timetamp
     * @return array()
     * **/
    private function get_all_user_info($last_timetamp) {
        $result = array();
        if (empty($last_timetamp)) {
            return $result;
        }
        //销售部
        $sale_department = APF::get_instance()->get_config('sale_department');
        //开通打卡机的城市
        $city_card = APF::get_instance()->get_config('city_card');
        $city_names = array_values($city_card);
        $city = " AND city_name IN('".implode("','", $city_names)."')";

        $lastday = date('Y-m-d',$last_timetamp)." 00:00:00";
        $start = 0;
        $limit = 100;
        while(true) {
            $sql = "SELECT user_id,user_type,user_type_date,enter_date,city_name,department_id FROM user_info WHERE user_id > {$start} AND (dimission_date = '0000-00-00 00:00:00' OR dimission_date >= '{$lastday}') {$city} ORDER BY user_id asc limit {$limit}";
            $tmp = $this->get_db_rows($sql,$this->writedb,array());
            if(empty($tmp)) {
                $this->log("取完所有用户数据!");
                break;
            }
            $count = count($tmp);
            $start = $tmp[$count - 1]['user_id'];
            $result = array_merge($result,$tmp);
        }
        //过滤未入职员工
        foreach ($result as $index => $value){
            $enter_time = strtotime($value['enter_date']);
            if($enter_time >= $last_timetamp){
                unset($result[$index]);
                continue;
            }
            if(!empty($sale_department[$value['department_id']])){
                unset($result[$index]);
                continue;
            }
        }
        return $result;
    }

    /**
     *根据用户id,获取打卡记录
     *@params array $uids
     *@return array
     * **/
    private function get_user_access_day_record($uids = array()) {
        $result = array();
        if (empty($uids)) {
            return $result;
        }
        $uids = implode(',',$uids);
        $sql = "SELECT user_id,start_work,end_work FROM access_day_record WHERE user_id in ({$uids}) AND access_date = {$this->date}";
        $tmp = $this->get_db_rows($sql,$this->writedb,array());
        if($tmp) {
            foreach ($tmp as $key => $val) {
                $result[$val['user_id']] = $val;
            }
        }
        return $result;
    }

}
